﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ICSharpCode.AvalonEdit.Highlighting;
using System.Xml;
using System.IO;
using ICSharpCode.AvalonEdit.CodeCompletion;
using ICSharpCode.AvalonEdit.Folding;
using System.Windows.Threading;
using ICSharpCode.AvalonEdit.Document;
using ExORMDesginer.Services;
using ExORMDesginer.Models;
using ExORMDesginer.Plugin;

namespace ExORMDesginer.UserControls.CCodeEditer
{

    public enum EditerType
    {
        CSharp,
        SQL
    }
    public interface IEditer
    {
        /// <summary>
        /// 设置文字 
        /// </summary>
        /// <param name="text"></param>
        void SetText(string text);
        /// <summary>
        /// 得到编辑器中的文字 
        /// </summary>
        /// <param name="text"></param>
        string GetText();
    }

    /// <summary>
    /// Interaction logic for CCodeEditer.xaml
    /// </summary>
    public partial class CCodeEditer : UserControl,IEditer
    {
        public static DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(CCodeEditer));

        public string Text
        {
            set
            {
                SetValue(TextProperty, value);
            }
            get
            {
               
                    return textEditor.Text;
                
               
            }
        }

        public string GetText()
        {
            string text = string.Empty;
           
            text = textEditor.Text;
            
            return text;
        }

        public void SetText(string str)
        {
            textEditor.Text = str;
        }


        public static DependencyProperty EditerTypeProperty = DependencyProperty.Register("EditerType", typeof(EditerType), typeof(CCodeEditer));
        public EditerType EditerType {
            set
            {
                SetValue(EditerTypeProperty, value);
            }
            get
            {
                return (EditerType)GetValue(EditerTypeProperty);
            }
        
        }

        static void TextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var that = d as CCodeEditer;
            if (e.NewValue != null)
                that.textEditor.Text = e.NewValue.ToString();
        }

        public static DependencyProperty InitTextProperty = DependencyProperty.Register("InitText",typeof(string),typeof(CCodeEditer), new PropertyMetadata(new PropertyChangedCallback(TextChanged)));

        public string InitText
        {
            set
            {
                SetValue(InitTextProperty, value);
            }
            get
            {
                return textEditor.Text;
            }
        }
        public CCodeEditer(EditerType type):this()
        {
            this.EditerType = type;
            Init();
            
        }

        public CCodeEditer()
        {
            InitializeComponent();
            
        }

        public void Init()
        {
            try
            {
                

                if (EditerType == UserControls.CCodeEditer.EditerType.SQL)
                {
                    // Load our custom highlighting definition
                    IHighlightingDefinition customHighlighting;
                    using (Stream s = typeof(CCodeEditer).Assembly.GetManifestResourceStream("ExORMDesginer.UserControls.CCodeEditer.SQL.xshd"))
                    {
                        if (s == null)
                            throw new InvalidOperationException("Could not find embedded resource");
                        using (XmlReader reader = new XmlTextReader(s))
                        {
                            customHighlighting = ICSharpCode.AvalonEdit.Highlighting.Xshd.
                                HighlightingLoader.Load(reader, HighlightingManager.Instance);
                        }
                    }
                    // and register it in the HighlightingManager
                    HighlightingManager.Instance.RegisterHighlighting("SQL", new string[] { ".sql" }, customHighlighting);


                    textEditor.SyntaxHighlighting = customHighlighting;

                    textEditor.TextArea.TextEntering += textEditor_TextArea_TextEntering;
                    textEditor.TextArea.TextEntered += textEditor_TextArea_TextEntered;
                    textEditor.KeyDown += new KeyEventHandler(textEditor_KeyDown);
                    textEditor.MouseHover += new MouseEventHandler(TextEditorMouseHover);
                    textEditor.MouseHoverStopped += new MouseEventHandler(TextEditorMouseHoverStopped);
                }
                else if (EditerType == UserControls.CCodeEditer.EditerType.CSharp)
                {
                    textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinition("C#");
                }
                DispatcherTimer foldingUpdateTimer = new DispatcherTimer(DispatcherPriority.Normal,this.Dispatcher);
                foldingUpdateTimer.Interval = TimeSpan.FromSeconds(2);
                foldingUpdateTimer.Tick += foldingUpdateTimer_Tick;
                foldingUpdateTimer.Start();

                textEditor.TextArea.IndentationStrategy = new ICSharpCode.AvalonEdit.Indentation.CSharp.CSharpIndentationStrategy(textEditor.Options);
                foldingStrategy = new BraceFoldingStrategy();

                if (foldingStrategy != null)
                {
                    if (foldingManager == null)
                        foldingManager = FoldingManager.Install(textEditor.TextArea);
                    foldingStrategy.UpdateFoldings(foldingManager, textEditor.Document);
                }
                else
                {
                    if (foldingManager != null)
                    {
                        FoldingManager.Uninstall(foldingManager);
                        foldingManager = null;
                    }
                }

            }
            catch { }

        }

      

        void textEditor_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyStates == Keyboard.GetKeyStates(Key.J) && Keyboard.Modifiers == ModifierKeys.Control)
            {
             
                
                cm.ShowCompletion(textEditor.TextArea, null);
            }
        }


        CompletionManager cm = new DataBaseCompletionManager();

        void textEditor_TextArea_TextEntered(object sender, TextCompositionEventArgs e)
        {
            if (e.Text == ".")
            {
                string tableNameWord = WordUtilities.GetDotPreviousWord(textEditor.TextArea);

                cm.ShowCompletion(textEditor.TextArea, tableNameWord);
          
            }
            else if(e.Text == " ")
            {
                string word = WordUtilities.FindPreviousWord(textEditor.TextArea);
                switch(word.ToLower())
                {
                    case "from":
                    case "join":
                    case "on":
                        cm.ShowCompletion(textEditor.TextArea, null);
                        break;


                }
            }
           SetValue(TextProperty, textEditor.Text);
        }


        ToolTip toolTip = new ToolTip();

        void TextEditorMouseHover(object sender, MouseEventArgs e)
        {
            var pos = textEditor.GetPositionFromPoint(e.GetPosition(textEditor));
            if (pos != null)
            {
                toolTip.PlacementTarget = this; // required for property inheritance
                var docLine = textEditor.TextArea.Document.Lines[pos.Value.Line - 1];
                int startOfWord = TextUtilities.GetNextCaretPosition(textEditor.TextArea.Document, docLine.Offset + pos.Value.Column, LogicalDirection.Backward, CaretPositioningMode.WordBorderOrSymbol);

                int endOfWord = TextUtilities.GetNextCaretPosition(textEditor.TextArea.Document, docLine.Offset + pos.Value.Column, LogicalDirection.Forward,
                                                                   CaretPositioningMode.WordBorder);

                
            
                string msg = null;
                if(startOfWord < endOfWord && startOfWord >= 0)
                    msg = textEditor.TextArea.Document.GetText(startOfWord, endOfWord - startOfWord);

                if (!string.IsNullOrEmpty(msg) && !msg.Contains(' '))
                {
                    for (int index = startOfWord; index >= 0; index--)
                    {
                        char wordChar = textEditor.TextArea.Document.GetCharAt(index);
                        if (wordChar == ' ' || wordChar == '\r' || wordChar == '\n')
                        {
                            msg = textEditor.TextArea.Document.GetText(index, endOfWord - index).Trim();
                            break;
                        }
                    }
             
                    string[] tc = msg.Split('.');
                    var isn = ServiceManager.GetService<DatabaseMetaService>();
                    if (isn == null) return;
                    var dict = isn.GetContext() as Dictionary<string, DbEntity>;
                    DbEntity entity = null;
                    if (dict.TryGetValue(tc[0].ToString(), out entity))
                    {
                        if (tc.Length > 1)
                        {
                            string fieldName = tc[1];
                            var property= entity.Propertys.First(p => p.Name == fieldName);
                            msg = string.Format("表名:{0},备注:{1},类型:{2}", property.Name, property.Memo,property.DataType);

                        }
                        else
                        {
                            msg = string.Format("表名:{0},字段数:{1},", entity.Name, entity.Propertys.Count);
                        }
                    }
                   
                 
                 
                    //msg = string.Format("表名:{0},字段数:{1},", entity.Name, entity.Propertys.Count);
                }
                else
                    msg = null;
              

                toolTip.Content = msg;
                toolTip.IsOpen = true;
                e.Handled = true;
            }
        }

        void TextEditorMouseHoverStopped(object sender, MouseEventArgs e)
        {
            toolTip.IsOpen = false;
        }


        void textEditor_TextArea_TextEntering(object sender, TextCompositionEventArgs e)
        {
            if (e.Text.Length > 0 && cm.completionWindow != null)
            {
                if (!char.IsLetterOrDigit(e.Text[0]))
                {
                    // Whenever a non-letter is typed while the completion window is open,
                    // insert the currently selected element.
                    cm.completionWindow.CompletionList.RequestInsertion(e);
                }
            }
            // do not set e.Handled=true - we still want to insert the character that was typed
        }

        #region Folding
        FoldingManager foldingManager;
        AbstractFoldingStrategy foldingStrategy;

       

        void foldingUpdateTimer_Tick(object sender, EventArgs e)
        {
            if (foldingStrategy != null)
            {
                foldingStrategy.UpdateFoldings(foldingManager, textEditor.Document);
            }
        }
        #endregion






      
    }
}
